package dipl.algorithm.math.primitive;

import dipl.algorithm.math.utility.ApfloatUtils;
import org.apfloat.Apfloat;

/**
 *
 */
public class Interval1d {

	//
	// CONSTRUCTOR METHODS
	//

	public Interval1d() {
		l = ApfloatUtils._0;
		u = ApfloatUtils._0;
	}

	public Interval1d( Apfloat a, Apfloat b ) {
		l = a.compareTo( b ) <= 0 ? a : b;
		u = a.compareTo( b ) >  0 ? a : b;
	}

  public Interval1d( Interval1d o ) {
		this.l = o.l;
		this.u = o.u;
  }

	//
	// PROPERTIES
	//

	/**
	 * 
	 */
	public static Interval1d EmptyInterval() {
		return new Interval1d( ApfloatUtils._0, ApfloatUtils._0 );
	}

  /**
	 *  lower interval border
	 */
	public Apfloat L() {
		return l;
	}

	/**
	 * interval length
	 */
	public Apfloat Length() {
		return u.subtract( l );
	}

	/**
	 * upper interval border
	 */
	public Apfloat U() {
		return u;
	}

	/**
	 * unit interval [0.0,1.0]
	 */
	public static Interval1d UnitInterval() {
		return new Interval1d( ApfloatUtils._0, ApfloatUtils._1 );
	}

	//
  // PUBLIC METHODS
	//

	/**
	 * Tests whether or not given value x is contained in interval
	 * @param x
	 * @return contained or not
	 */
	public boolean ContainsValue( Apfloat x ) {
		return (l.compareTo( x ) <= 0 && x.compareTo( u ) <= 0);
	}

	@Override
	@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
	public boolean equals( Object obj ) {
		Interval1d o = (Interval1d)obj;
		return (o.l.compareTo( this.l ) == 0 && o.u.compareTo( this.u ) == 0 );
	}

	@Override
	public int hashCode() {
		return super.hashCode();
	}

	/**
	 * Tests whether or not interval intersects with given one.
	 * @param other
	 * @return
	 */
	public boolean Intersects( Interval1d other ) {
		return u.compareTo( other.l ) >= 0 && l.compareTo( other.u ) <= 0;
	}

	/**
	 * Tests whether or not interval properly intersects with given one.
	 * @param other
	 * @return
	 */
	public boolean ProperlyIntersects( Interval1d other ) {
		return (u.compareTo( other.l ) > 0 && l.compareTo( other.u ) < 0);
	}

	/**
	 * Tests whether interval lies left of given point a
	 * @param a
	 * @return
	 */
	public boolean LeftOf( Apfloat a ) {
		return (u.compareTo( a ) < 0);
	}

	/**
	 * Tests whether interval lies right of given point a
	 * @param a
	 * @return
	 */
	public boolean RightOf( Apfloat a ) {
		return (l.compareTo( a ) > 0);
	}

	/**
	 * Sets bounds of interval. Use method if it is known that l < u
	 * @param l
	 * @param u
	 */
	public void SetBoundsUnsafe( Apfloat l, Apfloat u ) {
		this.l = l;
		this.u = u;
	}

	/**
	 * Sets bounds of interval. It is checked which value is smaller.
	 * @param a
	 * @param b
	 */
	public void SetBoundsSafe( Apfloat a, Apfloat b ) {
		l = a.compareTo( b ) <= 0 ? a : b;
		u = a.compareTo( b ) >  0 ? a : b;
	}

	/**
	 * Sets lower bound of interval. Use method if it is known that given l < this.u
	 * @param l
	 */
	public void SetLUnsafe( Apfloat l ) {
		this.l = l;
	}

	/**
	 * Sets upper bound of interval. Use method if it is known that given this.l < u
	 * @param u
	 */
	public void SetUUnsafe( Apfloat u ) {
		this.u = u;
	}

	@Override
	public String toString() {
		return "["+l.doubleValue()+", "+u.doubleValue()+"]";
	}

	//
	// MEMBERS
	//

	/** l interval border */
	private Apfloat l;
	/** u interval border */
	private Apfloat u;

	//
	// STATIC MEMBERS
	//
}

